package lwf.web.struts.action;

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lwf.handler.IProcessHandler;
import net.lwf.common.constant.ICommonConstant;
import net.lwf.entity.FormBasicInfo;
import net.lwf.entity.KnowledgeResource;
import net.lwf.entity.WebUser;
import net.lwf.exception.AppException;
import net.lwf.exception.ExceptionUtil;
import net.lwf.hibernate.entity.User;
import net.lwf.jaxb.service.TabMenuServiceFactory;
import net.lwf.pdf.IPdfConstant;
import net.lwf.pdf.util.LwfHeaderFooter;
import net.lwf.pdf.util.LwfWaterMarkText;
import net.lwf.string.util.StringManipulator;
import net.lwf.util.web.WebUtil;
import net.lwf.web.constant.IWebConstant;
import net.lwf.web.struts.action.UserDataHelper;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PdfWriter;



public abstract class BaseAction extends DispatchAction {

	private String grade;
	private String operation;

    /** User password. */
    public static byte[] USER = "Hello".getBytes(); //TODO From Lookup Table; To the Base Action Class
    /** Owner password. */
    public static byte[] OWNER = "World".getBytes(); //TODO From Lookup Table; To the Base Action Class
    
    public abstract String getPageTitle();	//TODO Should be merged into LWFWorksheetAction
    public abstract String getMainTitle(); 	//TODO Should be merged into LWFWorksheetAction
	public abstract String getPdfLink(); 	//TODO Should be merged into LWFWorksheetAction
	public abstract String getQuizLink();	//TODO Should be merged into LWFWorksheetAction
	
	public abstract IProcessHandler getHandler(HttpServletRequest request);
	
	public ActionForward execute(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response)
			throws Exception {
		//this.printReqData(request);
		//Temporary for the primary login
		Object pl_object = WebUtil.getAttribute(request, "IS_PRIMARY_LOGIN");
		if(pl_object == null) {
			return mapping.findForward("primarylogin");
		}
		
		request.removeAttribute(IWebConstant.KNOWLEDGE_RESOURCES);	//Safe guard	
		if(!isValidUser(request)) {
			return mapping.findForward("login");
		}
		try {
			UserDataHelper.checkGrSubTop(request); //Check if the user changes grade or change in subject in req or change in topic in the request
						
			this.grade = this.getWebUser(request).getUser().getGrade();
			this.processOperation(request); //Similar code in LwfWorkSheetAction commented out
			//Set Title, main title, pdf link etc.
			this.setBasicFormInfo(request);
			//Set Knowledge Resources
			this.setKnowledgeResources(request);
			
			return super.execute(mapping, form, request, response);
		}
		catch(RuntimeException rex) {
			ExceptionUtil.logAndThrowException(BaseAction.class, rex);
		}
		return null;
		//return super.execute(mapping, form, request, response);
	}
	
	public String getGrade() {
		return this.grade;
	}
	
/*	public void setOperation(HttpServletRequest request) {
		this.operation = request.getParameter(IWebConstant.OPERATION);
		if(operation != null) {
			WebUtil.setAttribute(request, IWebConstant.OPERATION, operation);	
		}
		
	}

	public String getOperation() {
		return WebUtil.getAttribute(request, IWebConstant.OPERATION, operation);
	}*/
	private boolean isValidUser(HttpServletRequest request) {
		WebUser webuser = (WebUser) WebUtil.getAttribute(request, IWebConstant.WEB_USER);
		
		if(webuser != null ) {
			User user = webuser.getUser();
			if(user != null && user.getUserId() != null) {
				return true;
			}
		}
		return false;
	}
	
	public WebUser getWebUser(HttpServletRequest request) {
		return UserDataHelper.getWebUser(request);
	}
	
	//------------------------------------------------------------------------------------------------------------
	// For Dynamic PDF generation
	//-----------------------------------------------------------------------------------------------------------
	
	/**
	 * Generates the PDF content and writes directly onto the browser. The pdf contents are
	 * per the handler.
	 * 
	 * @param mapping
	 * @param form
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public ActionForward generatePdf(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) {
		
		//Set the Content type - Mandatory
//		response.setContentType("application/pdf"); 
		
		IProcessHandler handler = getHandler(request);
		Document document = handler.getDocument();
		response.setContentType("application/pdf"); 
		//More added
		response.setHeader("Expires", "0");
		response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
		response.setHeader("Pragma", "public");
		//response.setContentLength(document.s)
		
		try{
			//Use the following to write the response to the browser
			PdfWriter writer = PdfWriter.getInstance(document, response.getOutputStream());
			 
			//Add header and footer
			String absolute_hip = getServlet().getServletContext().getRealPath(IPdfConstant.HEADER_IMAGE_PATH); 
			
			writer.setPageEvent(new LwfHeaderFooter(absolute_hip));
			
			//Add watermark
			writer.setPageEvent(new LwfWaterMarkText());		
			
			//Set encryption details to the file
			//String pdfOwner = LookupFactory.getInstance().getValue(IDalConstant.SECURITY, IDalConstant.PDF_OWNER_KEY);
/*			
 Commented as this is the root cause for the generated PDF content not to display on the browser - 03/20/12
 
 String pdfOwner = new LookupService().getValue(IDalConstant.SECURITY, IDalConstant.PDF_OWNER_KEY);
			writer.setEncryption(null, pdfOwner.getBytes(), PdfWriter.ALLOW_PRINTING, PdfWriter.ENCRYPTION_AES_128 | PdfWriter.DO_NOT_ENCRYPT_METADATA);*/

			//Write contents to an output file - optional - possible
			
			//Set the image path to the handler
			String baseImagePath = StringManipulator.replace(absolute_hip, IPdfConstant.HEADER_IMAGE_PATH, ICommonConstant.EMPTY);
			handler.setBaseImagePath(baseImagePath);
			//------------------------------------------------------------------------------------ Generate PDF Content
			handler.generate(document);
			//response.setContentType("application/pdf"); 
			return null;
		}
		catch(IOException ioex){
			ExceptionUtil.logAndThrowException(BaseAction.class, ioex);
		}
		catch(DocumentException dex){
			ExceptionUtil.logAndThrowException(BaseAction.class, dex);
		}
		catch(RuntimeException rex) {
/*			
 			//TODO Check why this will not work
			response.setContentType("text/html");
			AppException appex = ExceptionUtil.logException(BaseAction.class, rex);
			request.setAttribute("exceptionID", appex.getUniqueID());
//			ActionForward forward = mapping.findForward("pdfgenerationerror");
//			System.out.println("---------------> Forward name: " + forward.getName());
//			System.out.println("---------------> Forward path: " + forward.getPath());
//			System.out.println("---------------> Forward module: " + forward.getModule());
			return mapping.findForward("pdfgenerationerror");*/
			
			String nextJSP = "/lwf/error/pdfgenerationerror.jsp";

			AppException appex = ExceptionUtil.logException(BaseAction.class, rex);
			WebUtil.setAttribute(request, "exceptionID", appex.getUniqueID());
			//request.setAttribute("exceptionID", appex.getUniqueID());
			try {
				response.sendRedirect(nextJSP);
			} catch (IOException ioex) {
				ExceptionUtil.logAndThrowException(BaseAction.class, ioex);
			}
		}
		return null;
		
	}
	
	//------------------------------------------------------------------------------------------------------------
	// Common
	//-----------------------------------------------------------------------------------------------------------
	public void setBasicFormInfo(HttpServletRequest request) {
		if(getOperation() != null) {
			FormBasicInfo info = new FormBasicInfo();
			if(StringUtils.isNotEmpty(getPageTitle())) {
				info.setPageTitle(getPageTitle());
			}
			if(StringUtils.isNotEmpty(getMainTitle())) {
				info.setMainTitle(getMainTitle());
			}
			if(StringUtils.isNotEmpty(getPdfLink())) {
				info.setPdfLink(getPdfLink());
			}
			if(StringUtils.isNotEmpty(getQuizLink())) {
				info.setQuizLink(getQuizLink());
			}
			request.setAttribute(IWebConstant.BASIC_FORM_INFO, info);
		}
	}
	
	private void setKnowledgeResources(HttpServletRequest request) {
		if(getOperation() != null) {
			KnowledgeResource kr 
				= TabMenuServiceFactory.getInstance().getResources(getGrade(), getSubject(request), getTopic(request), getOperation(request));
			//List<Item> utubeResources = kr.getUtubeResources();
			if(kr != null) {
				request.setAttribute(IWebConstant.KNOWLEDGE_RESOURCES, kr);
			}
		}
	}
	
	public String getGrade(HttpServletRequest request) {
		return getWebUser(request).getUser().getGrade();
	}
	
	public String getSubject(HttpServletRequest request) {
		//return WebUtil.getMustParameter(request, IWebConstant.SUBJECT);
		return (String) WebUtil.getAttribute(request, IWebConstant.SUBJECT);
	}
	
	public String getTopic(HttpServletRequest request) {
		//return WebUtil.getMustParameter(request, IWebConstant.TOPIC);
		return (String) WebUtil.getAttribute(request, IWebConstant.TOPIC);
	}

	public String getOperation(HttpServletRequest request) {
		return (String) WebUtil.getAttribute(request, IWebConstant.OPERATION);
	}
	
	private void processOperation(HttpServletRequest request) {
		this.operation = request.getParameter(IWebConstant.OPERATION);
		if(this.operation != null) {
			WebUtil.setAttribute(request, IWebConstant.OPERATION, request.getParameter(IWebConstant.OPERATION));
		}
		else {
			Object obj = WebUtil.getAttribute(request, IWebConstant.OPERATION);
			if(obj != null) {
				this.operation = (String) obj;
			}
			else {
				//Set operation to default
				//TODO check later if it is needed or not 10/13/2011
				this.operation = IWebConstant.DEFAULT_OPERATION;
				WebUtil.setAttribute(request, IWebConstant.OPERATION, this.operation);
			}
		}
	}
	
	public String getOperation() {
		return this.operation;
	}
	
/*	private void printReqData(HttpServletRequest request) {
		System.out.println("================== Request URL: " + request.getRequestURL());
		System.out.println("================== Request URI: " + request.getRequestURI());
		System.out.println("================== Local Address: " + request.getLocalAddr());
		System.out.println("================== Local Name: " + request.getLocalName());
		System.out.println("================== Local Port: " + request.getLocalPort());
		System.out.println("================== Protocol: " + request.getProtocol());
		System.out.println("================== Query String: " + request.getQueryString());
	}*/
} //BaseAction

/*
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.util.MessageResources;

*//**
 * <p>An abstract <strong>Action</strong> that dispatches to a public
 * method that is named by the request parameter whose name is specified
 * by the <code>parameter</code> property of the corresponding
 * ActionMapping.  This Action is useful for developers who prefer to
 * combine many similar actions into a single Action class, in order to
 * simplify their application design.</p>
 *
 * <p>To configure the use of this action in your
 * <code>struts-config.xml</code> file, create an entry like this:</p>
 *
 * <code>
 *   &lt;action path="/saveSubscription"
 *           type="org.apache.struts.actions.DispatchAction"
 *           name="subscriptionForm"
 *          scope="request"
 *          input="/subscription.jsp"
 *      parameter="method"/&gt;
 * </code>
 *
 * <p>which will use the value of the request parameter named "method"
 * to pick the appropriate "execute" method, which must have the same
 * signature (other than method name) of the standard Action.execute
 * method.  For example, you might have the following three methods in the
 * same action:</p>
 * <ul>
 * <li>public ActionForward delete(ActionMapping mapping, ActionForm form,
 *     HttpServletRequest request, HttpServletResponse response)
 *     throws Exception</li>
 * <li>public ActionForward insert(ActionMapping mapping, ActionForm form,
 *     HttpServletRequest request, HttpServletResponse response)
 *     throws Exception</li>
 * <li>public ActionForward update(ActionMapping mapping, ActionForm form,
 *     HttpServletRequest request, HttpServletResponse response)
 *     throws Exception</li>
 * </ul>
 * <p>and call one of the methods with a URL like this:</p>
 * <code>
 *   http://localhost:8080/myapp/saveSubscription.do?method=update
 * </code>
 *
 * <p><strong>NOTE</strong> - All of the other mapping characteristics of
 * this action must be shared by the various handlers.  This places some
 * constraints over what types of handlers may reasonably be packaged into
 * the same <code>DispatchAction</code> subclass.</p>
 *
 * <p><strong>NOTE</strong> - If the value of the request parameter is empty,
 * a method named <code>unspecified</code> is called. The default action is
 * to throw an net.lwf.exception. If the request was cancelled (a <code>html:cancel</code>
 * button was pressed), the custom handler <code>cancelled</code> will be used instead.
 * You can also override the <code>getMethodName</code> method to override the action's
 * default handler selection.</p>
 *
 * @version $Rev: 384089 $ $Date: 2006-03-08 01:50:52 +0000 (Wed, 08 Mar 2006) $
 *//*
public class BaseAction extends DispatchAction {


    // ----------------------------------------------------- Instance Variables


    *//**
     * The Class instance of this <code>DispatchAction</code> class.
     *//*
    protected Class clazz = this.getClass();


    *//**
     * Commons Logging instance.
     *//*
    protected static Log log = LogFactory.getLog(DispatchAction.class);


    *//**
     * The message resources for this package.
     *//*
    protected static MessageResources messages =
            MessageResources.getMessageResources
            ("org.apache.struts.actions.LocalStrings");


    *//**
     * The set of Method objects we have introspected for this class,
     * keyed by method name.  This collection is populated as different
     * methods are called, so that introspection needs to occur only
     * once per method name.
     *//*
    protected HashMap methods = new HashMap();


    *//**
     * The set of argument type classes for the reflected method call.  These
     * are the same for all calls, so calculate them only once.
     *//*
    protected Class[] types =
            {
                ActionMapping.class,
                ActionForm.class,
                HttpServletRequest.class,
                HttpServletResponse.class};



    // --------------------------------------------------------- Public Methods


    *//**
     * Process the specified HTTP request, and create the corresponding HTTP
     * response (or forward to another web component that will create it).
     * Return an <code>ActionForward</code> instance describing where and how
     * control should be forwarded, or <code>null</code> if the response has
     * already been completed.
     *
     * @param mapping The ActionMapping used to select this instance
     * @param form The optional ActionForm bean for this request (if any)
     * @param request The HTTP request we are processing
     * @param response The HTTP response we are creating
     *
     * @net.lwf.exception Exception if an net.lwf.exception occurs
     *//*
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
            throws Exception {
        if (isCancelled(request)) {
            ActionForward af = cancelled(mapping, form, request, response);
            if (af != null) {
                return af;
            }
        }

        // Get the parameter. This could be overridden in subclasses.
        String parameter = getParameter(mapping, form, request, response);

        // Get the method's name. This could be overridden in subclasses.
        String name = getMethodName(mapping, form, request, response, parameter);


	// Prevent recursive calls
	if ("execute".equals(name) || "perform".equals(name)){
		String message =
			messages.getMessage("dispatch.recursive", mapping.getPath());

		log.error(message);
		throw new ServletException(message);
	}


        // Invoke the named method, and return the result
        return dispatchMethod(mapping, form, request, response, name);

    }



    
    *//**
     * Method which is dispatched to when there is no value for specified
     * request parameter included in the request.  Subclasses of
     * <code>DispatchAction</code> should override this method if they wish
     * to provide default behavior different than throwing a ServletException.
     *//*
    protected ActionForward unspecified(
            ActionMapping mapping,
            ActionForm form,
            HttpServletRequest request,
            HttpServletResponse response)
            throws Exception {

        String message =
                messages.getMessage(
                        "dispatch.parameter",
                        mapping.getPath(),
                        mapping.getParameter());

        log.error(message);

        throw new ServletException(message);
    }

    *//**
     * Method which is dispatched to when the request is a cancel button submit.
     * Subclasses of <code>DispatchAction</code> should override this method if
     * they wish to provide default behavior different than returning null.
     * @since Struts 1.2.0
     *//*
    protected ActionForward cancelled(ActionMapping mapping,
                                      ActionForm form,
                                      HttpServletRequest request,
                                      HttpServletResponse response)
            throws Exception {

        return null;
    }

    // ----------------------------------------------------- Protected Methods


    *//**
     * Dispatch to the specified method.
     * @since Struts 1.1
     *//*
    protected ActionForward dispatchMethod(ActionMapping mapping,
                                           ActionForm form,
                                           HttpServletRequest request,
                                           HttpServletResponse response,
                                           String name) throws Exception {

        // Make sure we have a valid method name to call.
        // This may be null if the user hacks the query string.
        if (name == null) {
            return this.unspecified(mapping, form, request, response);
        }

        // Identify the method object to be dispatched to
        Method method = null;
        try {
            method = getMethod(name);

        } catch(NoSuchMethodException e) {
            String message =
                    messages.getMessage("dispatch.method", mapping.getPath(), name);
            log.error(message, e);

            String userMsg =
                messages.getMessage("dispatch.method.user", mapping.getPath());
            throw new NoSuchMethodException(userMsg);
        }

        ActionForward forward = null;
        try {
            Object args[] = {mapping, form, request, response};
            forward = (ActionForward) method.invoke(this, args);

        } catch(ClassCastException e) {
            String message =
                    messages.getMessage("dispatch.return", mapping.getPath(), name);
            log.error(message, e);
            throw e;

        } catch(IllegalAccessException e) {
            String message =
                    messages.getMessage("dispatch.error", mapping.getPath(), name);
            log.error(message, e);
            throw e;

        } catch(InvocationTargetException e) {
            // Rethrow the target net.lwf.exception if possible so that the
            // net.lwf.exception handling machinery can deal with it
            Throwable t = e.getTargetException();
            if (t instanceof Exception) {
                throw ((Exception) t);
            } else {
                String message =
                        messages.getMessage("dispatch.error", mapping.getPath(), name);
                log.error(message, e);
                throw new ServletException(t);
            }
        }

        // Return the returned ActionForward instance
        return (forward);
    }

    *//**
     * <p>Returns the parameter value.</p>
     *
     * @param mapping  The ActionMapping used to select this instance
     * @param form     The optional ActionForm bean for this request (if any)
     * @param request  The HTTP request we are processing
     * @param response The HTTP response we are creating
     * @return The <code>ActionMapping</code> parameter's value
     * @throws Exception if the parameter is missing.
     *//*
    protected String getParameter(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {

        // Identify the request parameter containing the method name
        String parameter = mapping.getParameter();

        if (parameter == null) {
            String message =
                messages.getMessage("dispatch.handler", mapping.getPath());

            log.error(message);

            throw new ServletException(message);
        }


        return parameter;
    }

    *//**
     * Introspect the current class to identify a method of the specified
     * name that accepts the same parameter types as the <code>execute</code>
     * method does.
     *
     * @param name Name of the method to be introspected
     *
     * @net.lwf.exception NoSuchMethodException if no such method can be found
     *//*
    protected Method getMethod(String name)
            throws NoSuchMethodException {

        synchronized(methods) {
            Method method = (Method) methods.get(name);
            if (method == null) {
                method = clazz.getMethod(name, types);
                methods.put(name, method);
            }
            return (method);
        }

    }

    *//**
     * Returns the method name, given a parameter's value.
     *
     * @param mapping The ActionMapping used to select this instance
     * @param form The optional ActionForm bean for this request (if any)
     * @param request The HTTP request we are processing
     * @param response The HTTP response we are creating
     * @param parameter The <code>ActionMapping</code> parameter's name
     *
     * @return The method's name.
     * @since Struts 1.2.0
     *//*
    protected String getMethodName(ActionMapping mapping,
                                   ActionForm form,
                                   HttpServletRequest request,
                                   HttpServletResponse response,
                                   String parameter)
            throws Exception {

        // Identify the method name to be dispatched to.
        // dispatchMethod() will call unspecified() if name is null
        return request.getParameter(parameter);
    }

}*/
